home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
MENU_UTL
/
BMENU
/
BMENU.PAS
next >
Wrap
Pascal/Delphi Source File
|
1990-09-07
|
11KB
|
316 lines
unit BMenu; { John Haluska CIS 74000,1106 } { Turbo Pascal 5.5 }
{ Ver 1.0 8/15/90 Released to the public domain. }
{ BMenu contains objects to generate a Lotus style bar menu where each menu
item can be selected by the cursor/enter keys or a specified character.
Menu items are stored as a linked list in the heap. Typical use:
1. Declare a MMenuPtr variable: M : MMenuPtr;
Declare a char variable to receive the menu select character: Ch : char;
2. Initialize the menu to setup the linked list, define select characters
(1 for each menu item), and menu item background/text colors:
New(M,Init('ABCD',Red*16+LightGray));
3. Initialize the screen column/row position and title for each menu item
in order of the select character:
M^.Append(New(MItemPtr,Init(5,5, ' A Item ')));
M^.Append(New(MItemPtr,Init(15,5,' B Item ')));
M^.Append(New(MItemPtr,Init(25,5,' C Item ')));
M^.Append(New(MItemPtr,Init(35,5,' D Item ')));
4. Display the menu with the initial choice "A" hilited. Then return the
Esc character if the Esc key is pressed or the select character if the
cursor/enter keys or a select character is pressed:
Ch := M^.MenuPick('A');
5. Deallocate heap memory or deallocate heap memory and remove the menu
from the screen:
Dispose(M,Done); or Dispose(M,EraseMenu); }
interface
uses Crt,Objects; { Objects unit from TP5.5 OOPDEMOS.ARC }
type
MItemPtr = ^MItem;
MItem = object(Node) { Node from the Object unit }
C : byte; { Menu item screen start column location }
R : byte; { Menu item screen row location }
PTitle : ^string; { Menu item title }
constructor Init(Col,Row : word; Title : string);
destructor Done; virtual
end;
MMenuPtr = ^MMenu;
MMenu = object(List) { List from the Object unit }
NormVid,RevVid : byte;
SelStr : ^string;
constructor Init(SelChStr : string; NormVideo: byte);
function MenuPick(InitCh : char) : char;
destructor Done; virtual;
destructor EraseMenu;
function Specific(N : word) : NodePtr;
function Cardinal : word
end;
procedure ErrorTone;
function ReadValidChar(S : string) : char;
procedure CursorOn(State : boolean);
implementation
{----------------------------------------------------------------------------}
{ ErrorTone generates a 120Hz tone for .1 second. }
procedure ErrorTone;
begin
Sound(120); Delay(100); NoSound
end;
{----------------------------------------------------------------------------}
{ ReadValidChar reads and validates a keystroke against uppercase ASCII
characters, defined in string S, until a valid character is entered.
Lowercase letters (a-z) are returned as uppercase (A-Z). Extended scan
codes < 128 are returned with 128 added to the scan code. For example, F1
with a scan code 59 is returned as 187. A character not in S is ignored
and the tone is sounded. Example: The expression VK := ReadValidChar('ABC')
will return A, B, or C if the corresponding key is pressed or sound a tone
if any other key is pressed. }
function ReadValidChar(S : string) : char;
var
C,Cs : char;
OK : boolean;
begin
repeat
OK := false;
C := UpCase(ReadKey);
case C of
#1..#127 : if Pos(C,S) <> 0 then OK := true else ErrorTone;
#0 : begin
Cs := ReadKey;
if Ord(Cs) < 128 then
begin
C := Chr(Ord(Cs) + 128);
if Pos(C,S) <> 0 then OK := true else ErrorTone
end
else ErrorTone
end
else ErrorTone
end;
until OK;
ReadValidChar := C
end; {ReadValidChar}
{----------------------------------------------------------------------------}
{ CursorOn turns off (False) or turns on (True) the screen display cursor.
Example: CursorOn(False) turns off (hides) the cursor. }
procedure CursorOn(State : boolean);
begin
inline(
$B4/$03/ { MOV AH,3 ;Call BIOS Service 10h/3 -}
$B7/$00/ { MOV BH,0 ; Get Cursor Position}
$CD/$10/ { INT $10 ; & Size}
$8A/$96/>State/ { MOV DL,>State[BP] ;Save cursor on/off in DL}
$0A/$D2/ { OR DL,DL ;Turn cursor off?}
$74/$06/ { JZ X1 ;Yes}
$81/$E1/$FF/$DF/ { AND CX,$DFFF ;No, turn off bit 5 of CH}
$EB/$04/ { JMP SHORT X2 }
$81/$C9/$00/$20/ {X1: OR CX,$2000 ;Yes, turn on bit 5 of CH}
$B4/$01/ {X2: MOV AH,1 ;Call BIOS Service 10h/1 -}
$CD/$10) { INT $10 ; Set Cursor Size}
end; {CursorOn}
{----------------------------------------------------------------------------}
{ Initialize menu item with screen location (Col, Row) and Title. }
constructor MItem.Init(Col,Row : word; Title : string);
begin
GetMem(PTitle,Length(Title)+1);
C := Col;
R := Row;
PTitle^ := Title
end;
{----------------------------------------------------------------------------}
{ Remove item data from heap. }
destructor MItem.Done;
begin
FreeMem(PTitle,Length(PTitle^) + 1)
end;
{----------------------------------------------------------------------------}
{ Specific sets and returns the address of the Nth list item. Returns nil
if the list is empty or N is greater than the total items in the list. }
function MMenu.Specific(N : word) : NodePtr;
var
Np : NodePtr;
I : word;
begin
if N = 0 then
Specific := nil
else
begin
Np := First; { 1st object in list }
I := 1;
while (I < N) and (Np <> nil) do
begin
Np := Next(Np); { next object in list }
Inc(I)
end;
Specific := Np
end
end;
{----------------------------------------------------------------------------}
{ Cardinal returns the number of items (0 - 65535) in the list. After
returning, the list current item is the last item. }
function MMenu.Cardinal : word;
var
Np : NodePtr;
N : word;
begin
N := 0;
Np := First; { 1st object in list }
if Np <> nil then
repeat
Inc(N);
Np := Next(Np); { next object in list }
until Np = nil;
Cardinal := N
end;
{----------------------------------------------------------------------------}
{ Init initializes the menu object. SelChStr defines the characters that are
selected and returned by a menu item. NormVideo is the non-hilited menu
item background/text colors and uses the same format as Crt unit variable
TextAttr. }
constructor MMenu.Init(SelChStr : string; NormVideo : byte);
begin
Clear; {init linked list}
if LastMode = Mono then NormVid := Black shl 4 + LightGray {mono display}
else NormVid := NormVideo;
RevVid := (NormVid shr 4) and 7 + (NormVid shl 4) and $70; {hilite colors}
GetMem(SelStr,Length(SelChStr)+1);
SelStr^ :=SelChStr
end;
{----------------------------------------------------------------------------}
{ MenuPick displays the menu and then returns the character of the menu item
selected by the cursor/enter keys or the select character. InitCh is the
menu item hilited when MenuPick is called. The select characters are
defined by the Init constructor. Esc (#27) is returned if the Esc key is
pressed. Null (#0) is returned if the list is empty or the SelChStr string
length doesn't equal the number of menu items. }
function MMenu.MenuPick(InitCh : char) : char;
var
Choice,Ch : char;
ListLen,LastPick,CurPick,I : word;
Term : string;
{-------}
procedure HiLite(On : boolean; Num : integer) ;
var
Mp : MItemPtr;
begin
Mp := MItemPtr(Specific(Num));
GoToXY(Mp^.C,Mp^.R);
if On then
begin
TextAttr := RevVid;
Write(Mp^.PTitle^);
TextAttr := NormVid;
end
else
begin
TextAttr := NormVid;
Write(Mp^.PTitle^)
end
end; {HiLite}
{--------}
begin
ListLen := Cardinal; {number of items in the list}
I := Length(SelStr^);
if (I <> 0) and (I = ListLen) then
begin
CursorOn(false);
Term := SelStr^ + #13 + #27;
LastPick := Pos(InitCh,SelStr^);
if LastPick = 0 then LastPick := 1; {make sure InitChoice is valid}
CurPick := LastPick;
for I := 1 to ListLen do {display menu}
if I = CurPick then HiLite(true,I) else HiLite(false,I);
Choice := SelStr^[CurPick]; {initial choice}
HiLite(true,CurPick);
repeat
Ch := ReadValidChar(SelStr^+#13+#27+#199+#200+#201+#203+#205+#207+
#208+#209);
LastPick := CurPick;
if Pos(Ch,SelStr^) <> 0 then {Ch in 1st char string}
begin
Choice := Ch;
CurPick := Pos(Ch,SelStr^)
end
else {Ch not in 1st char string}
begin
case Ch of
#208,#205 : if LastPick < ListLen then CurPick := LastPick+1
else CurPick := 1; {Dn/Right Arrow}
#200,#203 : if LastPick > 1 then {Up/Left Arrow}
CurPick := LastPick-1
else
CurPick := ListLen;
#199,#201 : CurPick := 1; {Home/PgUp}
#207,#209 : CurPick := ListLen {End/PgDn}
end;
Choice := SelStr^[CurPick]
end;
if LastPick <> CurPick then
begin
HiLite(false,LastPick);
HiLite(true,CurPick)
end;
until Pos(Ch,Term) <> 0;
CursorOn(true);
if Ch = #27 then MenuPick := #27 {Esc}
else MenuPick := Choice
end
else
MenuPick := #0
end; {MenuPick}
{----------------------------------------------------------------------------}
{ EraseMenu clears the menu from the display by writing spaces using the
current value of Crt gobal unit variable TextAttr. Then the data is
deallocated from heap memory. }
destructor MMenu.EraseMenu;
var
Mp : MItemPtr;
begin
Mp := MItemPtr(First);
while (Mp <> nil) do
begin
GoToXY(Mp^.C,Mp^.R);
Write(' ':Length(Mp^.PTitle^));
Mp := MItemPtr(Next(Mp))
end;
Done
end;
{----------------------------------------------------------------------------}
{ Done deallocates data from heap memory. }
destructor MMenu.Done;
begin
FreeMem(SelStr,Length(SelStr^)+1);
Delete
end;
{----------------------------------------------------------------------------}
end. {BMenu}